#include <stdio.h>

int main(int argc, char **argv)
{
    // puts()函数用于将参数字符串显示在屏幕（stdout）上，并且自动在字符串末尾添加换行符。
    puts("io test:");

    int i, j;
    float x, y;
    // scanf()处理数值占位符时，会自动过滤空白字符，包括空格、制表符、换行符等。所以，用户输入的数据之间，有一个或多个空格不影响scanf()解读数据。另外，用户使用回车键，将输入分成几行，也不影响解读。
    // scanf()处理用户输入的原理是，用户的输入先放入缓存，等到按下回车键后，按照占位符对缓存进行解读。解读用户输入时，会从上一次解读遗留的第一个字符开始，直到读完缓存，或者遇到第一个不符合条件的字符为止。
    int readCount = scanf("%d%d%f%f", &i, &j, &x, &y);
    printf("read %d data\n", readCount);
    printf("%d %d %f %f\n", i, j, x, y);

    {
        int x;
        float y;

        // 用户输入 "    -13.45e12# 0"
        int readCount = scanf("%d", &x);
        printf("read %d data\n", readCount);
        readCount = scanf("%f", &y);
        printf("read %d data\n", readCount);
        // 上面示例中，scanf()读取用户输入时，%d占位符会忽略起首的空格，从-处开始获取数据，读取到-13停下来，因为后面的.不属于整数的有效字符。这就是说，占位符%d会读到-13。
        // 第二次调用scanf()时，就会从上一次停止解读的地方，继续往下读取。这一次读取的首字符是.，由于对应的占位符是%f，会读取到.45e12，这是采用科学计数法的浮点数格式。后面的#不属于浮点数的有效字符，所以会停在这里。
        printf("%d %f\n", x, y); // -13 449999994880.000000

        // 下面要特别说一下占位符%s，它其实不能简单地等同于字符串。它的规则是，从当前第一个非空白字符开始读起，直到遇到空白字符（即空格、换行符、制表符等）为止。因为%s不会包含空白字符，所以无法用来读取多个单词，除非多个%s一起使用。这也意味着，scanf()不适合读取可能包含空格的字符串，比如书名或歌曲名。另外，scanf()遇到%s占位符，会在字符串变量末尾存储一个空字符\0。
        // scanf()将字符串读入字符数组时，不会检测字符串是否超过了数组长度。所以，储存字符串时，很可能会超过数组的边界，导致预想不到的结果。为了防止这种情况，使用%s占位符时，应该指定读入字符串的最长长度，即写成%[m]s，其中的[m]是一个整数，表示读取字符串的最大长度，后面的字符将被丢弃。
        char name[11];
        readCount = scanf("%10s", name);
        printf("read %d data\n", readCount);

        printf("%s\n", name);

        // 赋值忽略符
        int year, month, day;
        scanf("%d-%d-%d", &year, &month, &day);
        printf("%d %d %d\n", year, month, day);
        // 上面示例中，如果用户输入2020-01-01，就会正确解读出年、月、日。问题是用户可能输入其他格式，比如2020/01/01，这种情况下，scanf()解析数据就会失败。
        // 为了避免这种情况，scanf()提供了一个赋值忽略符（assignment suppression character）*。只要把*加在任何占位符的百分号后面，该占位符就不会返回值，解析后将被丢弃。
        scanf("%d%*c%d%*c%d", &year, &month, &day); // 输入: 2023/12/31 下句输出: 2023 12 31
        // 上面示例中，%*c就是在占位符的百分号后面，加入了赋值忽略符*，表示这个占位符没有对应的变量，解读后不必返回。
        printf("%d %d %d\n", year, month, day);

        // sscanf()函数与scanf()很类似，不同之处是sscanf()从字符串里面，而不是从用户输入获取数据。
        sscanf("    -13.45e12# 0", "%d%f", &x, &y);
        printf("%d %f\n", x, y);

        // getchar()不会忽略起首的空白字符，总是返回当前读取的第一个字符，无论是否为空格。如果读取失败，返回常量 EOF，由于 EOF 通常是-1，所以返回值的类型要设为 int，而不是 char。
        int ch = getchar();

        // putchar()函数将它的参数字符输出到屏幕，等同于使用printf()输出一个字符
        putchar(ch);
        // 由于getchar()和putchar()这两个函数的用法，要比scanf()和printf()更简单，而且通常是用宏来实现，所以要比scanf()和printf()更快。如果操作单个字符，建议优先使用这两个函数。
    }
    return 0;
}